/***************************************************************************
      File Name:  StringHelpers.cs
   File Created:  Wednesday, June 13th 2007
      Copyright:  (C) 2007 by Darko Matesic
          Email:  darko.matesic@yahoo.com
 ***************************************************************************/

using System;
using System.Text;
using System.Text.RegularExpressions;

namespace CallerID.Helpers
{
    public class StringHelpers
    {
        /// <summary>
        /// Replaces special characters in string with specific escape string that can be later restored:
        /// '\\' -> "\\\\"
        /// '\r' -> "\\r"
        /// '\n' -> "\\n"
        /// '\t' -> "\\t"
        /// </summary>
        public static string EscapeSpecialCharacters(string text)
        {
            if(text == null) return null;
            System.Text.StringBuilder result = new System.Text.StringBuilder();
            for(int i = 0; i < text.Length; i++) {
                if(text[i] == '\\') {
                    result.Append("\\\\");
                } else if(text[i] == '\r') {
                    result.Append("\\r");
                } else if(text[i] == '\n') {
                    result.Append("\\n");
                } else if(text[i] == '\t') {
                    result.Append("\\t");
                } else {
                    result.Append(text[i]);
                }
            }
            return result.ToString();
        }

        /// <summary>
        /// Restores special characters in string that where replaced using ReplaceSpecialCharacters method.
        /// Restoration is performed using following patterns:
        /// "\\\\" -> '\\'
        /// "\\r" -> '\r'
        /// "\\n" -> '\n'
        /// "\\t" -> '\t'
        /// </summary>
        public static string RestoreSpecialCharacters(string text)
        {
            if(text == null) return null;
            System.Text.StringBuilder result = new System.Text.StringBuilder();
            for(int i = 0; i < text.Length; i++) {
                if(text[i] == '\\' && i < (text.Length - 1)) {
                    if(text[i + 1] == '\\') {
                        result.Append("\\"); i++;
                    } else if(text[i + 1] == 'r') {
                        result.Append("\r"); i++;
                    } else if(text[i + 1] == 'n') {
                        result.Append("\n"); i++;
                    } else if(text[i + 1] == 't') {
                        result.Append("\t"); i++;
                    } else {
                        result.Append(text[i]);
                    }
                } else {
                    result.Append(text[i]);
                }
            }
            return result.ToString();
        }

        /// <summary>
        /// Generates string where only first letter of every word is in uppercase.
        /// If specified, it can replace underscores with spaces
        /// </summary>
        public static string CreateTitle(string text, bool replaceUnderscore)
        {
            StringBuilder title = new StringBuilder();
            text = text.ToUpper();
            bool firstLetter = true;
            for(int i = 0; i < text.Length; i++) {
                string letter = text.Substring(i, 1);
                if(letter == "_") {
                    if(replaceUnderscore) title.Append(' '); else title.Append('_');
                    firstLetter = true;
                } else if(firstLetter) {
                    title.Append(letter);
                    firstLetter = false;
                } else {
                    title.Append(letter.ToLower());
                }
            }
            return title.ToString();
        }

        /// <summary>
        /// Left of the first occurance of c
        /// </summary>
        public static string LeftOf(string src, char c)
        {
            int idx = src.IndexOf(c);
            if(idx == -1) return src;
            return src.Substring(0, idx);
        }

        /// <summary>
        /// Left of the n'th occurance of c
        /// </summary>
        public static string LeftOf(string src, char c, int n)
        {
            int idx = -1;
            while(n != 0) {
                idx = src.IndexOf(c, idx + 1);
                if(idx == -1) return src;
                --n;
            }
            return src.Substring(0, idx);
        }

        /// <summary>
        /// Right of the first occurance of c
        /// </summary>
        public static string RightOf(string src, char c)
        {
            int idx = src.IndexOf(c);
            if(idx == -1) return "";
            return src.Substring(idx + 1);
        }

        /// <summary>
        /// Right of the n'th occurance of c
        /// </summary>
        public static string RightOf(string src, char c, int n)
        {
            int idx = -1;
            while(n != 0) {
                idx = src.IndexOf(c, idx + 1);
                if(idx == -1) return "";
                --n;
            }
            return src.Substring(idx + 1);
        }

        /// <summary>
        /// Left of the last occurance of c
        /// </summary>
        public static string LeftOfRightmostOf(string src, char c)
        {
            int idx = src.LastIndexOf(c);
            if(idx == -1) return src;
            return src.Substring(0, idx);
        }


        /// <summary>
        /// Right of the last occurance of c
        /// </summary>
        public static string RightOfRightmostOf(string src, char c)
        {
            int idx = src.LastIndexOf(c);
            if(idx == -1) {
                return src;
            }
            return src.Substring(idx + 1);
        }


        /// <summary>
        /// Returns string within specified string that resides between specified start and end characters
        /// </summary>
        public static string Between(string src, char start, char end)
        {
            string res = String.Empty;
            int idxStart = src.IndexOf(start);
            if(idxStart != -1) {
                ++idxStart;
                int idxEnd = src.IndexOf(end, idxStart);
                if(idxEnd != -1) {
                    res = src.Substring(idxStart, idxEnd - idxStart);
                }
            }
            return res;
        }

        /// <summary>
        /// Returns string within specified string that resides between specified start and end strings
        /// </summary>
        public static string Between(string src, string start, string end, bool includeStartEnd)
        {
            if(src != null && src.Length > 0 && start != null && start.Length > 0 && end != null && end.Length > 0) {
                int idxStart = src.IndexOf(start);
                if(idxStart >= 0) {
                    int idxEnd = src.IndexOf(end, idxStart + start.Length);
                    if(idxEnd >= idxStart) {
                        if(includeStartEnd) {
                            return src.Substring(idxStart, idxEnd - idxStart + end.Length);
                        } else {
                            return src.Substring(idxStart + start.Length, idxEnd - idxStart - start.Length);
                        }
                    }
                }
            }
            return String.Empty;
        }

        /// <summary>
        /// Returns number of occurances of specified character in specified string
        /// </summary>
        public static int Count(string src, char find)
        {
            int ret = 0;
            foreach(char s in src) if(s == find) ret++;
            return ret;
        }

        /// <summary>
        /// Checks if specified text1 is equal to specified text2 using specified search options.
        /// </summary>
        public static bool Equals(string text1, string text2, StringComparisonOptions options)
        {
            if(text1 == null && text2 == null) {
                return true;
            } else if(text1 != null && text2 != null) {
                if(text1.Length == 0 && text2.Length == 0) {
                    return true;
                }
                if((options & StringComparisonOptions.CaseInsensitive) == StringComparisonOptions.CaseInsensitive) {
                    text1 = text1.ToLower();
                    text2 = text2.ToLower();
                }
                if((options & StringComparisonOptions.Contains) == StringComparisonOptions.Contains) {
                    if(text1.Contains(text2)) return true;
                } else if((options & StringComparisonOptions.StartsWith) == StringComparisonOptions.StartsWith) {
                    if(text1.StartsWith(text2)) return true;
                } else if((options & StringComparisonOptions.EndsWith) == StringComparisonOptions.EndsWith) {
                    if(text1.EndsWith(text2)) return true;
                } else if(text1 == text2) {
                    return true;
                }
            }
            return false;
        }


        /// <summary>
        /// Compute Levenshtein distance between the two strings.
        /// The larger the number, the bigger the difference.
        /// </summary>
        public static int LevenshteinDistance(string s, string t)
        {
            int n = s.Length; //length of s
            int m = t.Length; //length of t
            int[,] d = new int[n + 1, m + 1]; // matrix
            int cost; // cost
            // Step 1
            if(n == 0) return m;
            if(m == 0) return n;
            // Step 2
            for(int i = 0; i <= n; d[i, 0] = i++) ;
            for(int j = 0; j <= m; d[0, j] = j++) ;
            // Step 3
            for(int i = 1; i <= n; i++) {
                //Step 4
                for(int j = 1; j <= m; j++) {
                    // Step 5
                    cost = (t.Substring(j - 1, 1) == s.Substring(i - 1, 1) ? 0 : 1);
                    // Step 6
                    d[i, j] = System.Math.Min(System.Math.Min(d[i - 1, j] + 1, d[i, j - 1] + 1), d[i - 1, j - 1] + cost);
                }
            }
            // Step 7
            return d[n, m];
        }


        /// <summary>
        /// Removes html tags from specified string.
        /// </summary>
        public static string RemoveTags(string text)
        {
            return Regex.Replace(text, @"<(.|\n)*?>", string.Empty).Replace("&nbsp;", " ");
        }
    }

    /// <summary>
    /// Search options.
    /// </summary>
    [Flags]
    public enum StringComparisonOptions
    {
        None = 0,
        /// <summary>
        /// String comparison is case insensitive.
        /// </summary>
        CaseInsensitive = 1,
        /// <summary>
        /// Searched item contains specified text.
        /// </summary>
        Contains = 2,
        /// <summary>
        /// Searched item starts with specified text.
        /// </summary>        
        StartsWith = 4,
        /// <summary>
        /// Search item ends with specified text.
        /// </summary>
        EndsWith = 8
    }
}
